﻿using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Text;

namespace PlutoStudio
{
    /// <summary>
    /// Json序列化及反序列化扩展方法类
    /// </summary>
    public static class JsonExtensions
    {
        private const char TypeSeperator = '|';

        /// <summary>
        /// 将指定的对象序列化成JSON字符串，并加入类型信息。
        /// 所以,它将可以在稍后使用 <see cref="DeserializeWithType"/> 方法反序列化。
        /// </summary>
        /// <param name="obj">要序列化的对象</param>
        /// <returns>生成的JSON字符串</returns>
        public static string SerializeWithType(this object obj)
        {
            return SerializeWithType(obj, obj.GetType());
        }

        /// <summary>
        /// 将指定的对象序列化成JSON字符串，并加入类型信息。
        /// 所以,它将可以在稍后使用 <see cref="DeserializeWithType"/> 方法反序列化。
        /// </summary>
        /// <param name="obj">要序列化的对象</param>
        /// <param name="type">对象的类型</param>
        /// <returns>生成的JSON字符串</returns>
        public static string SerializeWithType(this object obj, Type type)
        {
            var serialized = obj.Serialize();

            return string.Format(
                "{0}{1}{2}",
                type.AssemblyQualifiedName,
                TypeSeperator,
                serialized
                );
        }

        /// <summary>
        /// 反序列化使用 <see cref="SerializeWithType(object)"/> 方法序列化后的对象。
        /// </summary>
        /// <param name="serializedObj">要反序列化的JSON字符串</param>
        /// <typeparam name="T">对象的类型</typeparam>
        public static T DeserializeWithType<T>(this string serializedObj)
        {
            return (T)DeserializeWithType(serializedObj);
        }

        /// <summary>
        /// 反序列化使用 <see cref="SerializeWithType(object)"/> 方法序列化后的对象。
        /// </summary>
        /// <param name="serializedObj">要反序列化的JSON字符串</param>
        public static object DeserializeWithType(this string serializedObj)
        {
            var typeSeperatorIndex = serializedObj.IndexOf(TypeSeperator);
            var type = Type.GetType(serializedObj.Substring(0, typeSeperatorIndex));
            var serialized = serializedObj.Substring(typeSeperatorIndex + 1);

            var options = new JsonSerializerSettings();
            return JsonConvert.DeserializeObject(serialized, type, options);
        }

        /// <summary>
        /// 将JSON字符串反序列化成指定类型的对象。
        /// </summary>
        /// <typeparam name="T">对象的类型</typeparam>
        /// <param name="value">要反序列化的JSON字符串</param>
        /// <returns>反序列化生成的对象</returns>
        public static T Deserialize<T>(this string value)
        {
            return JsonConvert.DeserializeObject<T>(value);
        }

        /// <summary>
        /// 将JSON字符串反序列化成Object对象。
        /// </summary>
        /// <param name="value">要反序列化的JSON字符串</param>
        /// <returns>反序列化生成的对象</returns>
        public static object Deserialize(this string value)
        {
            return JsonConvert.DeserializeObject(value);
        }

        /// <summary>
        /// 将JSON字符串反序列化成指定类型的对象。
        /// </summary>
        /// <param name="value">要反序列化的JSON字符串</param>
        /// <param name="type">对象的类型</param>
        /// <returns>反序列化生成的对象</returns>
        public static object Deserialize(this string value, Type type)
        {
            return JsonConvert.DeserializeObject(value, type);
        }

        /// <summary>
        /// 将指定的对象序列化成JSON字符串。
        /// </summary>
        /// <param name="value">要序列化的对象</param>
        /// <returns>生成的JSON字符串</returns>
        public static string Serialize(this object value, bool camelCase = false, bool indented = false)
        {
            var options = new JsonSerializerSettings();

            if (camelCase)
            {
                options.ContractResolver = new CamelCasePropertyNamesContractResolver();
            }
            if (indented)
            {
                options.Formatting = Formatting.Indented;
            }
            return JsonConvert.SerializeObject(value, options);
        }
    }
}
